package com.gw.vip.center.sign;

import com.alibaba.fastjson.JSONObject;
import com.gw.vip.common.exception.ServiceException;
import com.gw.vip.common.util.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * @author GW
 * @version 1.0
 * @description
 * @since 2020/12/12 14:23
 */
@Service
@Slf4j
public class SignService {

    /**
     * 获取签名
     * @param json
     * @param key
     * @return
     */
    public String getSign(JSONObject json, String key){
        JSONObject jsonClone=json.clone();
        String signType=jsonClone.getString("signType");
        if (StringUtils.isBlank(signType)|| StringUtils.isBlank(key)){
            log.error("未知签名类型或则key");
            throw new ServiceException("未知签名类型或则key");
        }
        jsonClone.remove("sign");

        String context=getJsonOrderString(jsonClone);
        log.debug("签名字符串【{}】", context);

        SignCreatorEnums signCreatorEnums=SignCreatorEnums.getEnum(signType);
        if (signCreatorEnums==null){
            log.error("签名生成器不存在，类型【{}】", signType);
            throw new ServiceException("签名生成器不存在");
        }
        String creatorName=signCreatorEnums.getCreator();
        SignCreator signCreator= SpringContextHolder.getBean(creatorName);
        return signCreator.createSign(context, key);
    }

    /**
     * 验证签名
     * @param json
     * @param key
     */
    public void checkSign(JSONObject json, String key){
        String sign=json.getString("sign");
        String signCheckStr=this.getSign(json, key);

        if (!sign.equals(signCheckStr)){
            log.error("验签错误！");
            log.error("上送签名【{}】", sign);
            log.error("系统签名【{}】", signCheckStr);
            throw new ServiceException("验签错误！");
        }
    }

    //----------------------辅助函数------------------------//

    private static String getJsonOrderString(JSONObject json){
        List<String> list=new ArrayList<>();
        json.forEach((k, v)->{
            if (v instanceof String){
                list.add(k +'=' + v);
            }else if (v instanceof BigDecimal){
                list.add(k + '=' + v);
            }else if (v instanceof Integer){
                list.add(k +'=' + v);
            }else if (v instanceof Long){
                list.add(k +'=' + v);
            } else if (v instanceof JSONObject){
                JSONObject jsonV=(JSONObject)  v;
                list.add(k + '=' + getJsonOrderString(jsonV));
            }
        });
        list.sort(String::compareTo);
        return StringUtils.join(list, '&');
    }
}
